package br.com.lh.urabuilder.view.arrow
{
	import br.com.lh.urabuilder.domain.view.UraElement;
	import br.com.lh.urabuilder.domain.xml.UraActionWithNext;
	import br.com.lh.urabuilder.model.UraModelLocator;
	import br.com.lh.urabuilder.util.BestPointChooser;
	import br.com.lh.urabuilder.util.BorderDrawer;
	import br.com.lh.urabuilder.util.CoordinatesUtils;
	import br.com.lh.urabuilder.view.ActionComponent;
	
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.binding.utils.BindingUtils;
	import mx.binding.utils.ChangeWatcher;
	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	import mx.controls.Label;
	import mx.core.UIComponent;
	import mx.styles.StyleManager;
	
	[Bindable]
	public class ArrowContainer extends Canvas implements UraElement{
		
	
		public var startComponent:ActionComponent;
		public var endComponent:ActionComponent;
		private var selected:Boolean=false;
		public var arrowWrapper:ArrowWrapper = null;
		public var arrowText:Label;
		private var changeWatcherArray:Array = new Array();
		public static const HALF_CONTAINER_HEIGHT:Number=10;
		public static const END_OF_ARROW_PERCENT:Number = 0.7;
		public static const START_OF_ARROW_PERCENT:Number = 0.3;
		
		
		private const OFFSET_SELF_ARROW_HEIGHT:int = 10;
		
		public function ArrowContainer(startComponent:ActionComponent,endComponent:ActionComponent,text:String = ""){
			this.startComponent = startComponent;
			this.endComponent = endComponent;
			this.horizontalScrollPolicy = "off";
			this.verticalScrollPolicy = "off";
			startComponent.addOutArrow(this);
			endComponent.addEntryArrow(this);
			arrowText = new Label();
			arrowText.text = text;
			arrowText.styleName = StyleManager.getStyleDeclaration('AccordionHeader');
			drawContainer();
			bindMovement(startComponent);
			bindMovement(endComponent);
			addEventListener(MouseEvent.MOUSE_UP,selectObject);
			addEventListener(MouseEvent.MOUSE_DOWN,UraModelLocator.getInstance().arrowDragHelper.mouseDown);
			addEventListener(MouseEvent.MOUSE_MOVE,function (e:MouseEvent) : void {
			UraModelLocator.getInstance().arrowDragHelper.initDrag(e,true);});
			scaleX = UraModelLocator.getInstance().zoomManager.currentScale;
			scaleY = UraModelLocator.getInstance().zoomManager.currentScale;
		}
		
		
		
		public function selectObject(event:MouseEvent):void	{
			UraModelLocator.getInstance().viewManager.selectComponent(this,true,event.shiftKey);
			UraModelLocator.getInstance().mouseEventHelper.isMouseMovingArrow= false;
		}
		
		
		private function bindMovement(element:UIComponent):void{
			changeWatcherArray.push(BindingUtils.bindSetter(redrawArrows,element,"x"));
			changeWatcherArray.push(BindingUtils.bindSetter(redrawArrows,element,"y"));
		} 
		
		private function redrawArrows(val:Number):void{
			arrowWrapper.redrawArrow();
			startComponent.parent.removeChild(this);
			removeChild(arrowWrapper);
			removeChild(arrowText);
			drawContainer();
			BorderDrawer.drawBorder(this,isSelected());
		}
		
		private function drawContainer():void{
			var arrowBuilder:BestPointChooser = new BestPointChooser(startComponent,endComponent);
			var relativeStartPoint:Point;
			var relativeEndPoint:Point;
			var selfArrow:Boolean = this.selfArrow(); 
			if (selfArrow){
				this.height= CoordinatesUtils.SELF_ARROW_HEIGHT;
				this.width = (CoordinatesUtils.SELF_ARROW_WIDTH << 1);
				relativeStartPoint = new Point(this.width - (CoordinatesUtils.SELF_ARROW_WIDTH) - (startComponent.image.width >> 2),0);
				relativeEndPoint = relativeStartPoint;
			}
			else{
				this.height=HALF_CONTAINER_HEIGHT * 2;
				this.width = arrowBuilder.getLength() ;
				relativeStartPoint = new Point(0,(HALF_CONTAINER_HEIGHT));
				relativeEndPoint = new Point(width,(HALF_CONTAINER_HEIGHT));
			}
			this.addText(width,arrowBuilder);
			this.calculateInitialPoint(arrowBuilder,selfArrow);
			arrowWrapper = new ArrowWrapper(relativeStartPoint,relativeEndPoint,selfArrow);
			addChild(arrowWrapper);
			startComponent.parent.addChild(this);
		}
	
		public function selfArrow():Boolean{
			return startComponent == endComponent;
		}
	
		private function addText(width:Number,arrowBuilder:BestPointChooser):void{
			rotation = arrowBuilder.getAngleInDegrees();
			arrowText.x = width/2;
			arrowText.rotation = getCorrectOrientedAngle(rotation);
			addChild(arrowText);
		}
	
	
		private function calculateInitialPoint(arrowBuilder:BestPointChooser,selfArrow:Boolean):void{
			if (selfArrow){
				var start:Point = startComponent.image.contentToGlobal(new Point(startComponent.image.x,startComponent.image.y));
				this.x = start.x + startComponent.image.width;
				this.y = start.y + startComponent.image.height - CoordinatesUtils.getCanvasLocalToGlobalCoordinates().y + this.height + OFFSET_SELF_ARROW_HEIGHT;
			}
			else{
				var startPoint:Point = arrowBuilder.getPoints()[0];
				var startPointRotated:Point = CoordinatesUtils.getRotatedStartPoint(startPoint,HALF_CONTAINER_HEIGHT,arrowBuilder.getAngleInRad());
				this.x = startPointRotated.x; 
				this.y = startPointRotated.y; 
			}		
		}
	
		public function isSelected():Boolean{
			return selected;
		}
		
		private function getCorrectOrientedAngle(baseAngle:Number):Number{
			if (baseAngle >90 && baseAngle < 270){
				return -180;
			}
			return 0;
		}
		
		
		public function setSelected(selected:Boolean):void{
			this.selected = selected;
			BorderDrawer.drawBorder(this,selected);
		}
		
		public function remove():void{
			if (startComponent.uraAction is UraActionWithNext){
				var startAction:UraActionWithNext = UraActionWithNext(startComponent.uraAction);
				startAction.setNextId(-1);
				UraModelLocator.getInstance().xmlManager.unlinkElement(startAction);
			}
			arrowWrapper.remove();
			doRemove(startComponent.outArrows);
			doRemove(endComponent.entryArrows);
			removeBindings();
		}
		
		private function removeBindings():void{
			for each (var watcher:ChangeWatcher in changeWatcherArray){
				watcher.unwatch();
			}
		}
		
		private function doRemove(arrows:ArrayCollection):void{
			var index:Number = arrows.getItemIndex(this);
			if (index!= -1){
				arrows.removeItemAt(index);
			}
		}
		
		public function children():ArrayCollection{
			return new ArrayCollection;
		}
		
		
		
	}
}